
import spinal.core._
import spinal.lib._

class status_reg(reg:UInt,pos:Int,set_signal:Bool){
    val status = Reg(Bool) init(False)
    val clr = reg(pos)
    when(clr.edge){
        status := False
    }.elsewhen(set_signal.rise) {
        status := True
    }
}

case class ftsdc010_sim() extends Component {
    val io = new Bundle {
        val sdio_clk = out Bool()
        val sdio_cmd = inout(Analog(Bits(1 bits)))
        val sdio_dat = inout(Analog(Bits(4 bits)))

        val apb_psel = in Bool()
        val apb_addr = in UInt(32 bits)
        val apb_pwdata = in     UInt(32 bits)
        val apb_prdata = out    UInt(32 bits)
        val apb_pwrite = in Bool()
        val apb_ptran = in Bool()
        val apb_pready_o = out Bool()
    }


    val fifo_depth = 64
    noIoPrefix()

    val cmd        =  Reg(UInt(32 bits)) init(0) /* 0x00 - command reg        */
    val argu       =  Reg(UInt(32 bits)) init(0) /* 0x04 - argument reg       */
    val rsp0       =  Reg(UInt(32 bits)) init(0) /* 0x08 - response reg0      */
    val rsp1       =  Reg(UInt(32 bits)) init(0) /* 0x0c - response reg1      */
    val rsp2       =  Reg(UInt(32 bits)) init(0) /* 0x10 - response reg2      */
    val rsp3       =  Reg(UInt(32 bits)) init(0) /* 0x14 - response reg3      */
    val rsp_cmd    =  Reg(UInt(32 bits)) init(0) /* 0x18 - responded cmd reg  */
    val dcr        =  Reg(UInt(32 bits)) init(0) /* 0x1c - data control reg   */
    val dtr        =  Reg(UInt(32 bits)) init(10000000) /* 0x20 - data timer reg     */
    val dlr        =  Reg(UInt(32 bits)) init(0) /* 0x24 - data length reg    */
    val status     =  UInt(32 bits) /* 0x28 - status reg         */
    status.setName("status")
    val clr        =  Reg(UInt(32 bits)) init(0) /* 0x2c - clear reg          */
    val int_mask   =  Reg(UInt(32 bits)) init(0) /* 0x30 - intrrupt mask reg  */
    val pcr        =  Reg(UInt(32 bits)) init(0) /* 0x34 - power control reg  */
    val ccr        =  Reg(UInt(32 bits)) init(0) /* 0x38 - clock contorl reg  */
    val bwr        =  Reg(UInt(32 bits)) init(1) /* 0x3c - bus width reg      */
    val dwr        =  Reg(UInt(32 bits)) init(0) /* 0x40 - data window reg    */
    //val feature    =  Reg(UInt(32 bits)) init(0) /* 0x44 - feature reg        */
    val rev        =  Reg(UInt(32 bits)) init(0) /* 0x48 - revision reg       */
    val feature = U(
        32 bits,
        (7 downto 0) -> U(fifo_depth),
        default -> False
    )

    //不堵塞处理
    io.apb_pready_o := True


    //使用SDIO模块
    val sdio = new sdio
    io.sdio_clk := sdio.io.sdio_clk
    io.sdio_cmd := sdio.io.sdio_cmd
    io.sdio_dat := sdio.io.sdio_dat

    val recv_stream = Stream(Bits(32 bits))

    ////////////////////////
    //总线读取
    val     prdata = Reg(UInt(32 bits)) init(0)
    val     addr = UInt(6 bits)
    addr  := io.apb_addr(7 downto 2)
    io.apb_prdata := prdata

    val sdio_cmd          = cmd(5 downto 0)
    val sdio_cmd_need_rsp = cmd(6)
    val sdio_cmd_long_rsp = cmd(7)
    val sdio_cmd_app_cmd  = cmd(8)
    val sdio_cmd_en       = cmd(9)
    val sdio_sdc_rst      = Reg(Bool) init(False)// cmd(10)
    val sdio_mmc_int_stop = cmd(11)
    val sdio_bus_4bit     = bwr(2)

    val clr_rsp_crc_fail    = clr(0)
    val clr_dat_crc_fail    = clr(1)
    val clr_rsp_timeout     = clr(2)
    val clr_dat_timeout     = clr(3)
    val clr_rsp_crc_ok      = clr(4)
    val clr_dat_crc_ok      = clr(5)
    val clr_cmd_send        = clr(6)
    val clr_dat_end         = clr(7)

    sdio.io.sdio_clkdiv := (B"0" ## ccr(6 downto 0)).asSInt

    sdio.io.sdio_cmd_valu       := sdio_cmd
    sdio.io.sdio_cmd_argu       := argu
    sdio.io.sdio_cmd_need_rsp   := sdio_cmd_need_rsp
    sdio.io.sdio_cmd_long_rsp   := sdio_cmd_long_rsp
    sdio.io.sdio_bus_4bit       := sdio_bus_4bit

    //有关数据的
    val dat_remaining   = Reg(SInt(32 bits)) init(0)
    dat_remaining.setName("dat_remaining")
    sdio.io.sdio_dat_en :=      dcr(6) && (dat_remaining>0)
    sdio.io.sdio_dat_write :=   dcr(4)
    val dma_en =                dcr(5)     //不支持
    val block_size  = SInt(16 bits)
    val one_value = SInt(16 bits)
    one_value   := 1
    block_size  := (one_value << dcr(3 downto 0))(15 downto 0)

    sdio.io.timeout_tick  := dtr
    sdio.io.timeout_reset := (clr(2).edge) || (clr(3).edge)         //超时重置


    val cmd_en_trg = Reg(Bool) init(False)
    val cmd_en = Reg(Bool) init(False)
    //命令开启
    sdio.io.sdio_cmd_en  := cmd_en

    ///////////////////////
    //数据流
    val send_fifo = StreamFifo(Bits(32 bits), fifo_depth)
    val recv_fifo = StreamFifo(Bits(32 bits), fifo_depth)
    val send_stream = Stream(Bits(32 bits))
    val send_valid      = Reg(Bool()) init(False)
    val send_payload    = Reg(Bits(32 bits)) init(0)
    val dwr_read = io.apb_psel && io.apb_ptran && !io.apb_pwrite && (addr===16)
    val dwr_writ = io.apb_psel && io.apb_ptran && io.apb_pwrite && (addr===16)
    val recv_stream_data =  recv_stream.payload(7 downto 0) ##
                            recv_stream.payload(15 downto 8) ##
                            recv_stream.payload(23 downto 16) ##
                            recv_stream.payload(31 downto 24)

    send_stream.valid    := dwr_writ          //apb来传输fifo
    send_stream.payload  := //send_payload        //写入
                        io.apb_pwdata.asBits(7 downto 0) ##
                        io.apb_pwdata.asBits(15 downto 8) ##
                        io.apb_pwdata.asBits(23 downto 16) ##
                        io.apb_pwdata.asBits(31 downto 24)

    recv_stream.ready := dwr_read.rise         //每次读取触发一次

    send_fifo.io.pop  >> sdio.io.send_stream
    send_fifo.io.push << send_stream

    recv_fifo.io.pop  >> recv_stream
    recv_fifo.io.push << sdio.io.recv_stream

    recv_fifo.io.flush      :=      dcr(10)
    send_fifo.io.flush      :=      dcr(10)

    ///////////////////////////////////////////////////
    //处理状态.以及清除状态
    val status_rsp_crc_fail = new status_reg(clr,0,sdio.io.crc_rsp_fail);
    val status_dat_crc_fail = new status_reg(clr,1,sdio.io.crc_dat_fail);
    val status_rsp_timeout  = new status_reg(clr,2,sdio.io.timeout_rsp);
    val status_dat_timeout  = new status_reg(clr,3,sdio.io.timeout_dat);
    val status_rsp_crc_ok   = new status_reg(clr,4,sdio.io.crc_rsp_ok);
    val status_dat_crc_ok   = new status_reg(clr,5,sdio.io.crc_dat_ok);
    val status_cmd_send     = new status_reg(clr,6,sdio.io.cmd_send_done);      //由
    val status_dat_end      = new status_reg(clr,7,sdio.io.dat_end && dat_remaining<=0);
    //val ctrl_rst            = new status_reg(cmd,10,sdio.io.cmd_send_done);

    status := U(
        32 bits,
        0 -> status_rsp_crc_fail.status,
        1 -> status_dat_crc_fail.status,
        2 ->  status_rsp_timeout.status,
        3 ->  status_dat_timeout.status,
        4 ->   status_rsp_crc_ok.status,
        5 ->   status_dat_crc_ok.status,
        6 ->     status_cmd_send.status,
        7 ->      status_dat_end.status,
        9 ->          recv_stream.valid,            //数据有效则返回1
        8 ->          send_stream.ready,            //发送fifo为空
        11 ->         True,                            //sd挂载
        default -> False
    )

    val cmd_ret = UInt(32 bits)
    cmd_ret.setName("cmd_ret")
    //cmd_ret(10) := !ctrl_rst.status
    val sdc_rst = Reg(Bool) init(False)

    when(cmd(10).rise){
        //被设置为1,表示开始重启
        sdc_rst := False
    }
    .elsewhen(cmd(10) && sdio.io.cmd_send_done.rise){
        //重启结束
        sdc_rst := True
    }

    cmd_ret(10) := !sdc_rst
    cmd_ret(31 downto 11) := cmd(31 downto 11)
    cmd_ret(9 downto 0) := cmd(9 downto 0)

    val     read_data = addr.mux(
            0  -> (cmd_ret       ),/* 0x00 - command reg        */
            1  -> (argu          ),/* 0x04 - argument reg       */
            2  -> (sdio.io.sdio_rsp(32*1 + 8 -1 downto 32*0 + 8).asUInt ),/* 0x08 - response reg0      */
            3  -> (sdio.io.sdio_rsp(32*2 + 8 -1 downto 32*1 + 8).asUInt ),/* 0x0c - response reg1      */
            4  -> (sdio.io.sdio_rsp(32*3 + 8 -1 downto 32*2 + 8).asUInt ),/* 0x10 - response reg2      */
            5  -> (sdio.io.sdio_rsp(32*4 + 8 -1 downto 32*3 + 8).asUInt ),/* 0x14 - response reg3      */
            6  -> (rsp_cmd       ),/* 0x18 - responded cmd reg  */
            7  -> (dcr           ),/* 0x1c - data control reg   */
            8  -> (dtr           ),/* 0x20 - data timer reg     */
            9  -> (dat_remaining.asUInt),/* 0x24 - data length reg    */
            10 -> (status        ),/* 0x28 - status reg         */
            11 -> (clr           ),/* 0x2c - clear reg          */
            12 -> (int_mask      ),/* 0x30 - intrrupt mask reg  */
            13 -> (pcr           ),/* 0x34 - power control reg  */
            14 -> (ccr           ),/* 0x38 - clock contorl reg  */
            15 -> (bwr           ),/* 0x3c - bus width reg      */
            16 -> (recv_stream_data.asUInt),/* 0x40 - data window reg    */
            //0x44,0x48是其他版本的寄存器
            17 -> (feature       ),/* 0x44 - feature reg        */
            18 -> (rev           ), /* 0x48 - revision reg       */
            39 -> (feature       ),     //fifo
            40 -> (rev           ),
            default -> (U(0,32 bits))
        //
    )

    //////////////////////////////////////////
    //控制sdio
    val block_next      = Reg(Bool) init(False)             //控制下一个数据块的传输
    val dat_trg         = Reg(Bool) init(False)
    sdio.io.mmc_init        := sdio_sdc_rst.edge
    sdio.io.dat_next_en  := block_next
    sdio.io.block_size   := block_size

    ///////////////////////////////////////////////
    //发送命令
    when(cmd_en_trg.edge){
        //sdio.io.sdio_cmd_en     :=  sdio_cmd_en
        cmd_en := True
    }
    .otherwise{
        when(dat_trg.edge){
            //当写入dcr开启时触发,初始化
            dat_remaining   :=  dlr.asSInt
        }
        .elsewhen(sdio.io.dat_end.rise) {
            //清空
            //sdio.io.sdio_cmd_en := False
            when(dat_remaining>block_size){
                //如果还需要读写数据,则再次触发一次读取
                block_next      := True;
                dat_remaining   := dat_remaining - block_size
            }
            .otherwise{
                when(dat_remaining===block_size){
                    //不需要额外触发一次读写
                    //dat_en 被关闭
                    dat_remaining   := dat_remaining - block_size
                }
                block_next := False
            }
        }.otherwise{
            block_next := False
        }
        cmd_en := False
    }

    //控制数据传输

    when(io.apb_psel && io.apb_ptran){
        //处理
        when(!io.apb_pwrite){
            //read
            prdata := read_data
        }
        .otherwise{
            switch(addr){
                //write
                is(0 ){
                    /*
                    val sdio_cmd_en   = in Bool()
                    val sdio_cmd_valu = in UInt(6 bits)
                    val sdio_cmd_argu = in UInt(32 bits)
                    val sdio_cmd_need_rsp = in Bool()
                    val sdio_cmd_long_rsp = in Bool()
                    val sdio_rsp      = out Bits(256 bits)
                    val sdio_bus_4bit = in Bool()     //默
                    */
                    cmd             :=  io.apb_pwdata               //SDC_RST
                    sdio_sdc_rst    :=  sdio_sdc_rst ^ io.apb_pwdata(10)
                    when(io.apb_pwdata(10)){
                        //需要初始化一些寄存器
                        //dtr  := 10000000
                        dcr  := 9        //1<<9=512
                        ccr  := 0
                        //dlr  := 512
                        argu := 0
                    }
                    cmd_en_trg      :=  cmd_en_trg ^ io.apb_pwdata(9)
                    //触发读写
                }
                is(1 ){ argu     := io.apb_pwdata }
                is(2 ){ /* rsp0     := io.apb_pwdata */ }
                is(3 ){ /* rsp1     := io.apb_pwdata */ }
                is(4 ){ /* rsp2     := io.apb_pwdata */ }
                is(5 ){ /* rsp3     := io.apb_pwdata */ }
                is(6 ){ rsp_cmd  := io.apb_pwdata }
                is(7 ){
                    dcr      := io.apb_pwdata
                    dat_trg  :=  dat_trg ^ io.apb_pwdata(6)        //当需要传输数据的时候
                }
                is(8 ){
                    when(io.apb_pwdata===0){
                        dtr := 100000000
                    }
                    .otherwise{
                        dtr      := io.apb_pwdata
                    }
                }
                is(9 ){
                    dlr      := io.apb_pwdata
                    //dat_trg  := !dat_trg
                }
                is(10){ /* status   := io.apb_pwdata */ }
                is(11){ clr      := clr ^ io.apb_pwdata }
                is(12){ int_mask := io.apb_pwdata }
                is(13){ pcr      := io.apb_pwdata }
                is(14){ ccr      := io.apb_pwdata }
                is(15){ bwr      := io.apb_pwdata }
                is(16){
                    dwr             := io.apb_pwdata
                    send_payload    :=
                        io.apb_pwdata.asBits(7 downto 0) ##
                        io.apb_pwdata.asBits(15 downto 8) ##
                        io.apb_pwdata.asBits(23 downto 16) ##
                        io.apb_pwdata.asBits(31 downto 24)
                    send_valid      := !send_valid
                }
                is(17){ /* feature  := io.apb_pwdata */ }
                is(18){ /* rev      := io.apb_pwdata */ }
            }
        }
    }
}

object ftsdc010_gen {
    def main(args:Array[String]){
        //SpinalVerilog(new sdio)//.printPruned()

        SpinalConfig(
            mode=Verilog,
            //obfuscateNames=False
        ).generate(new ftsdc010_sim)

        //SpinalVerilog(StreamFifo(Bits(8 bits), 64))

    }
}

